/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANIUTIL_ERROR_H
#define ANIUTIL_ERROR_H

#include <ani.h>

#include <string>

#include "base.h"

namespace OHOS {
namespace AniUtil {

class ErrorFactory {
public:
    ErrorFactory(ani_env *env) : env_(env)
    {
    }

    expected<ani_error, ani_status> Create(int code, const std::string& message)
    {
        static const char *errorClsName = "L@ohos/base/BusinessError;";
        ani_status status = ANI_ERROR;
        ani_class cls;
        status = env_->FindClass(errorClsName, &cls);
        if (ANI_OK != status) {
            return status;
        }
        ani_method ctor;
        status = env_->Class_FindMethod(cls, "<ctor>", ":V", &ctor);
        if (ANI_OK != status) {
            return status;
        }
        ani_object obj;
        status = env_->Object_New(cls, ctor, &obj);
        if (ANI_OK != status) {
            return status;
        }
        ani_double aniCode = static_cast<ani_double>(code);
        ani_string aniMessage;
        status = env_->String_NewUTF8(message.c_str(), message.size(), &aniMessage);
        if (ANI_OK != status) {
            return status;
        }
        status = env_->Object_SetFieldByName_Double(obj, "code", aniCode);
        if (ANI_OK != status) {
            return status;
        }
        status = env_->Object_SetPropertyByName_Ref(obj, "message", aniMessage);
        if (ANI_OK != status) {
            return status;
        }
        return static_cast<ani_error>(obj);
    }

    ani_status Throw(int code, const std::string& message)
    {
        auto result = Create(code, message);
        if (!result.has_value()) {
            return result.error();
        }
        return env_->ThrowError(static_cast<ani_error>(result.value()));
    }

private:
    ani_env *env_ = nullptr;
};

} // namespace AniUtil
} // namespace OHOS

#endif
